﻿/*******************************************************************
** 文件名: IOCP_Server.h
** 版  权: (C) 深圳未名网络技术有限公司(664510732@qq.com)
** 创建人: DaiYuanzhi
** 日  期: 2021/03/28  17:58:17
** 版  本: 1.0
** 描  述:
** 应  用:

**************************** 修改记录 *******************************
** 修改人:
** 日  期:
** 描  述:
********************************************************************/

#ifndef __IOCP_SERVER_H__
#define __IOCP_SERVER_H__

#include "IIOCPServer.h"
//#include "SocketContext.h"

// 释放数据指针
#define RELEASE_ARRAY(x)  \
    {                     \
        if (x != nullptr) \
        {                 \
            delete[] x;   \
            x = nullptr;  \
        }                 \
    }

// 释放指针
#define RELEASE_POINTER(x) \
    {                      \
        if (x != nullptr)  \
        {                  \
            delete x;      \
            x = nullptr;   \
        }                  \
    }

// 释放句柄
#define RELEASE_HANDLE(x)                              \
    {                                                  \
        if (x != nullptr && x != INVALID_HANDLE_VALUE) \
        {                                              \
            CloseHandle(x);                            \
            x = nullptr;                               \
        }                                              \
    }

// 释放Socket
#define RELEASE_SOCKET(x)                     \
    {                                         \
        if (x != NULL && x != INVALID_SOCKET) \
        {                                     \
            closesocket(x);                   \
            x = INVALID_SOCKET;               \
        }                                     \
    }

// 地址长度
const auto MAX_SERVER_ADDR_LEN = 128;

// 最大监听连接个数
const auto MAX_LISTER_SOCKET = SOMAXCONN;

// 同时投递的AcceptEx请求的数量
const auto MAX_POST_ACCEPT = 10;

// 服务器监听IP
const auto DEFAULT_SERVER_IP = "127.0.0.1";

// 每个处理器上产生多少个线程
const auto WORKER_THREADS_PER_PROCESSOR = 2;

// // 多长时间（ ms ）没有数据就开始 send 心跳包
const auto KEEP_ALIVE_TIME = 1000 * 60;

// // 每隔多长时间（ ms ） send 一个心跳包
const auto KEEP_ALIVE_INTERVAL = 1000 * 10;

// 传递给工作线程退出信号
#define EXIT_CODE NULL

// 日志函数指针
typedef void (*LOG_FUNC)(const std::string& rstMsg);

class CIOCPServer;
struct SWorkerThreadParam
{
    CIOCPServer* m_pIOCPServer; //类指针，用于调用类中的函数
    DWORD m_dwThreadNo;         // 线程编号
    DWORD m_dwThreadID;         // 线程ID
};

class CIOCPServer : public IIOCPServer
{
public:
    CIOCPServer();

    virtual ~CIOCPServer();

public:
    // 启动服务
    virtual int OnStartServer(int nPort = DEFAULE_SERVER_PORT);

    // 停止服务
    virtual void OnStopServer();

    // 获得本机的IP地址
    virtual string GetLocalIP();

    // 获取处理器个数
    virtual int GetNumOfProcessors();

    // 获取当前连接数
    virtual int GetConnectCount();

    // 获取当前监听端口
    virtual unsigned int GetListerPort();

    // 在主界面中显示信息
    virtual void ShowMessage(const char* pszFormat, ...);

    // 投递成功
    virtual void OnConnectionAcceptedEvent(const SSocketContext* pSocketContext);

    // 连接关闭
    virtual void OnCloseConnectEvent(const SSocketContext* pSocketContext);

    // 连接错误
    virtual void OnConnectionErrorEvent(const SSocketContext* pSocketContext, int nErrID);

    // 接收完成
    virtual void OnRecvCompletedEvent(const SSocketContext* pSocketContext, const SIOContext* pIoContext);

    // 发送完成
    virtual void OnSendCompletedEvent(const SSocketContext* pSocketContext, const SIOContext* pIoContext);

private:
    // 初始化IOCP
    int InitializeIOCP();

    // 初始化ListenSocket
    int InitializeListenSocket();

    // 初始化Socket库
    int InitSocketLib();

    // 清除Socket库
    void CleanSocketLib();

    // 释放资源
    void Release();

    // 投递完成端口请求
    bool PostAccept(SIOContext* pIOContext);

    // 显示并处理IOCP上的错误
    bool HandleError(SSocketContext* pSoContext, DWORD dwErrID);

    // 判断客户端Socket是否已经断开
    bool IsSocketAlive(SOCKET uiSocketID);

    // 关闭连接
    bool CloseConnect(SSocketContext* pSocketContext);

    // 移除连接数据
    void RemoveSocketContext(SSocketContext* pSocketContext);

    // 将客户端的相关信息存储到数组中
    void AddSocketContext(SSocketContext* pSocketContext);

    // 清除客户端信息
    void ClearContextList();

    // 向指定客户端发送数据
    bool SendData(SSocketContext* pSocketContext, const char* pData, int nLen);

    // 发送数据.
    bool SendData(const SSocketContext* pSocketContext, SIOContext* pIoContext);

    // 继续接收指定客户端的数据
    bool RecvData(const SSocketContext* pSocketContext, SIOContext* pIoContext);

    // 在有接收的数据到达的时候，进行处理
    bool DoRecv(SSocketContext* pSocketContext, SIOContext* pIoContext);

    // 新的客户端接入
    bool DoAccept(SSocketContext* pSocketContext, SIOContext* pIOContext);

    // 发送数据
    bool DoSend(SSocketContext* pSocketContext, SIOContext* pIoContext);

private:
    // 线程回调函数
    static DWORD WINAPI WorkerThreadProc(LPVOID lpParam);

private:
    HANDLE m_hShutdownEvent;                             // 用来通知线程，为了能够更好的退出
    HANDLE m_hIOCompletionPort;                          // 完成端口的句柄
    HANDLE* m_phWorkerThreads;                           // 工作者线程的句柄指针
    int m_nThreadNum;                                    // 生成的线程数量
    char m_szServerAddr[MAX_SERVER_ADDR_LEN];            // 服务器端的IP地址
    int m_nListerPort;                                   // 服务器端的监听端口
    CRITICAL_SECTION m_csContextList;                    // 用于Worker线程同步的互斥量
    std::vector<SSocketContext*> m_stClientContextVect;  // 客户端Socket的Context信息
    SSocketContext* m_pListenSockContext;                // 用于监听的Socket的Context信息
    long m_nAcceptPostCount;                              // 当前投递的的Accept数量
    long m_nConnectCount;                                 // 当前的连接数量
    long m_nErrorCount;                                   // 当前的错误数量

    // AcceptEx 和 GetAcceptExSockaddrs 的函数指针，用于调用这两个扩展函数
    // GetAcceptExSockAddrs函数指针,win8.1以后才支持
    LPFN_GETACCEPTEXSOCKADDRS m_lpfnGetAcceptExSockAddrs;

    // AcceptEx函数指针,win8.1以后才支持
    LPFN_ACCEPTEX m_lpfnAcceptEx;

    // 日志函数指针
    LOG_FUNC m_lpLogFunc;
};

#endif // __IOCP_SERVER_H__
